<?php

 /**
  * @package JooS
  * @subpackage PHPackager
  */

  require_once "JooS/PHPackager/DOM/Element.php";

  class JooS_PHPackager_DOM_Element_Package extends JooS_PHPackager_DOM_Element {
    protected $_instructionsNodes = null;
    
    protected $_relationsNodes = null;

    protected $_name = null;

    protected $_version = null;

    protected $_properties = null;

    protected $_methods = null;

    /**
     * 
     */
    protected function makeName() {
      require_once "JooS/Syntax/Compiler.php";
      require_once "JooS/Syntax/PHPackager/DOM/Name.php";

      $_syntax = new JooS_Syntax_PHPackager_DOM_Name();
      $_name = $this->getNode()->getAttribute("name");
      $_nameValue = JooS_Syntax_Compiler::newInstance($_syntax)->compile($_name);
      
      if ($_nameValue === false || $_nameValue == "") {
        require_once "JooS/PHPackager/DOM/Exception.php";

        throw new JooS_PHPackager_DOM_Exception("Syntax error in project name: '$_name'");
      }
      else {
        $this->_name = $_nameValue;
      }
    }

    public function getName() {
      return $this->_name;
    }

    /**
     * 
     */
    protected function makeVersion() {
      require_once "JooS/Syntax/Compiler.php";
      require_once "JooS/Syntax/PHPackager/DOM/Version.php";

      $_syntax = new JooS_Syntax_PHPackager_DOM_Version();
      $_version = $this->getNode()->getAttribute("version");
      $_versionValue = JooS_Syntax_Compiler::newInstance($_syntax)->compile($_version);
      
      if ($_versionValue === false || $_versionValue == "") {
        require_once "JooS/PHPackager/DOM/Exception.php";

        throw new JooS_PHPackager_DOM_Exception("Syntax error in project version: '$_version'");
      }
      else {
        $this->_version = $_versionValue;
      }
    }

    /**
     * 
     */
    protected function makeInstructions() {
      $this->_instructionsNodes = array();
      
      $nodes = $this->query("child::add[processing-instruction()]|child::delete[processing-instruction()]", "JooS_PHPackager_DOM_Element_Tasks");
      foreach ($nodes as $k => $node) {
        /* @var $node JooS_PHPackager_DOM_Element_Tasks */

        $name = strtolower($node->getNode()->tagName);
        if (isset($this->_instructionsNodes[$name])) {
          require_once "JooS/PHPackager/DOM/Exception.php";

          throw new JooS_PHPackager_DOM_Exception("Not unique instruction node name: $name");
        }
        $this->_instructionsNodes[$name] = $node;

        $node->make();
      }

    }

    /**
     * 
     */
    protected function makeRelations() {
      $this->_relationsNodes = array();

      $nodes = $this->query("depends|provides|conflicts|breaks");
      foreach ($nodes as $node) {
        $name = strtolower($node->getNode()->tagName);
        if (isset($this->_relationsNodes[$name])) {
          require_once "JooS/PHPackager/DOM/Exception.php";

          throw new JooS_PHPackager_DOM_Exception("Not unique relation node name: $name");
        }
        $this->_relationsNodes[$name] = $node;

        $node->make();
      }
    }

    /**
     * @return JooS_PHPackager_DOM_Element_Package
     */
    public function make() {
      $this->makeName();
      $this->makeVersion();
      $this->makeInstructions();
      $this->makeRelations();

      $this->_properties = array();
      $this->_methods = array();

      return $this;
    }

    /**
     * @param JooS_Event_Phpackager_Package_Method_Create $event
     */
    public function addMethod(JooS_Event_Phpackager_Package_Method_Create $event) {
      $this->_methods[] = $event->method;
    }

    /**
     * @param JooS_Event_Phpackager_Package_Property_Create $event
     */
    public function addProperty(JooS_Event_Phpackager_Package_Property_Create $event) {
      $this->_properties[] = $event->property;
    }

    /**
     * @return JooS_PHPackager_DOM_Element_Package
     */
    public function install() {
      require_once "JooS/CodeGenerator/Property.php";
      require_once "JooS/CodeGenerator/Class.php";

      require_once "JooS/Event/Phpackager/Package/Method/Create.php";
      require_once "JooS/Event/Phpackager/Package/Property/Create.php";
      require_once "JooS/Event/Phpackager/Package/Source.php";

      $pkgDoc = new DOMDocument("1.0", "UTF-8");
      $pkgDoc->loadXML('<control />');

      $pkgDoc->documentElement->appendChild( $pkgDoc->importNode($this->getNode(), true) );

      $propertyName = JooS_CodeGenerator_Property::newInstance("_name")
        ->setVisibility(JooS_CodeGenerator_Property::VISIBILITY_PROTECTED)
        ->setValue($this->_name)
        ->setStatic(true);

      $propertyVersion = JooS_CodeGenerator_Property::newInstance("_version")
        ->setVisibility(JooS_CodeGenerator_Property::VISIBILITY_PROTECTED)
        ->setValue($this->_version)
        ->setStatic(true);

      $propertyControl = JooS_CodeGenerator_Property::newInstance("_control")
        ->setVisibility(JooS_CodeGenerator_Property::VISIBILITY_PROTECTED)
        ->setValue( trim($pkgDoc->saveXML()) )
        ->setStatic(true);

      JooS_Event_Phpackager_Package_Method_Create::getInstance()
        ->attach(array($this, "addMethod"));

      JooS_Event_Phpackager_Package_Property_Create::getInstance()
        ->attach(array($this, "addProperty"));

      JooS_Event_Phpackager_Package_Property_Create::getInstance()
        ->setProperty($propertyName)
        ->notify();
      
      JooS_Event_Phpackager_Package_Property_Create::getInstance()
        ->setProperty($propertyVersion)
        ->notify();
      
      JooS_Event_Phpackager_Package_Property_Create::getInstance()
        ->setProperty($propertyControl)
        ->notify();

      foreach ($this->_relationsNodes as $node) {
        $node->install();
      }
      foreach ($this->_instructionsNodes as $node) {
        $node->install();
      }

      $className = "JooSX_Package_" . $this->_name . "_" . str_replace(".", "_", $this->_version);
      
      $newClass = JooS_CodeGenerator_Class::newInstance($className)
        ->setExtendedClass("JooS_PHPackager_Instance");

      foreach ($this->_properties as $property) {
        $newClass->addProperty($property);
      }
      foreach ($this->_methods as $method) {
        $newClass->addMethod($method);
      }

      JooS_Event_Phpackager_Package_Source::getInstance()
        ->setClassName($className)
        ->setPackage($newClass)
        ->notify();

      JooS_Event_Phpackager_Package_Property_Create::getInstance()
        ->detach(array($this, "addProperty"));

      JooS_Event_Phpackager_Package_Method_Create::getInstance()
        ->detach(array($this, "addMethod"));

      return $this;
    }
  }
